package systemMapperImpl

import (
	"baize/app/baize"
	"baize/app/business/system/systemModels"
	"baize/app/datasource"
	"baize/app/utils/baizeContext"
	"context"
	"errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"

	"go.mongodb.org/mongo-driver/mongo"
)

type SysUserMapper struct {
	collection func(ctx context.Context) *mongo.Collection
}

func NewSysUserMapper(c *mongo.Client) *SysUserMapper {
	return &SysUserMapper{
		collection: func(ctx context.Context) *mongo.Collection {
			return c.Database(datasource.SysDatabase).Collection(datasource.Collection["user"])
		},
	}
}

func (userMapper *SysUserMapper) SelectUserNameByUserName(ctx context.Context, userName []string) (list []string) {
	filter := bson.M{"user_name": bson.M{"$in": userName}, "company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}

	opt := &options.FindOptions{}
	opt.SetProjection(bson.M{"_id": 0, "user_name": 1})

	cursor, err := userMapper.collection(ctx).Find(ctx, filter, opt)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	defer cursor.Close(ctx)
	for cursor.Next(ctx) {
		var result struct {
			UserName string `bson:"user_name"`
		}
		if err = cursor.Decode(&result); err != nil {
			panic(err)
		}
		list = append(list, result.UserName)
	}

	return list
}
func (userMapper *SysUserMapper) CheckUserNameUnique(ctx context.Context, userName string) int64 {
	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.D{{"_id", 1}})
	type IDOnly struct {
		ID int64 `bson:"_id"`
	}
	var result IDOnly
	err := userMapper.collection(ctx).FindOne(ctx, bson.M{"sys_user": userName, "company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}, opt).Decode(result)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return result.ID
}
func (userMapper *SysUserMapper) CheckPhoneUnique(ctx context.Context, phonenumber string) int64 {
	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.D{{"_id", 1}})
	type IDOnly struct {
		ID int64 `bson:"_id"`
	}
	var result IDOnly
	err := userMapper.collection(ctx).FindOne(ctx, bson.M{"phone_number": phonenumber, "company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}, opt).Decode(result)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return result.ID
}

func (userMapper *SysUserMapper) CheckEmailUnique(ctx context.Context, email string) int64 {
	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.D{{"_id", 1}})
	type IDOnly struct {
		ID int64 `bson:"_id"`
	}
	var result IDOnly
	err := userMapper.collection(ctx).FindOne(ctx, bson.M{"email": email, "company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}, opt).Decode(result)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return result.ID
}

func (userMapper *SysUserMapper) InsertUser(ctx context.Context, sysUser *systemModels.SysUserDML) {
	_, err := userMapper.collection(ctx).InsertOne(ctx, sysUser)
	if err != nil {
		panic(err)
	}
}
func (userMapper *SysUserMapper) BatchInsertUser(ctx context.Context, sysUser []*systemModels.SysUserDML) {

	users := make([]interface{}, 0, len(sysUser))
	for _, dml := range sysUser {
		users = append(users, dml)
	}
	_, err := userMapper.collection(ctx).InsertMany(ctx, users)
	if err != nil {
		panic(err)
	}
}

func (userMapper *SysUserMapper) UpdateUser(ctx context.Context, sysUser *systemModels.SysUserDML) {
	m := bson.M{
		"update_by":   sysUser.UpdateBy,
		"update_time": sysUser.UpdateTime,
		"update_name": sysUser.UpdateName,
	}

	if sysUser.Email != "" {
		m["email"] = sysUser.Email
	}
	if sysUser.DeptId != 0 {
		m["dept_id"] = sysUser.DeptId
	}

	if sysUser.DataScope != "" {
		m["data_scope"] = sysUser.DataScope
	}
	if sysUser.NickName != "" {
		m["nick_name"] = sysUser.NickName
	}
	if sysUser.Avatar != "" {
		m["avatar"] = sysUser.Avatar
	}
	if sysUser.Phonenumber != "" {
		m["phone_number"] = sysUser.Phonenumber
	}
	if sysUser.Sex != "" {
		m["sex"] = sysUser.Sex
	}
	if sysUser.Status != "" {
		m["status"] = sysUser.Status
	}

	up := bson.M{"$set": m}

	_, err := userMapper.collection(ctx).UpdateByID(ctx, sysUser.UserId, up)
	if err != nil {
		panic(err)
	}
}

func (userMapper *SysUserMapper) SelectUserByUserName(ctx context.Context, userName string, companyId int64) (loginUser *systemModels.User) {
	loginUser = new(systemModels.User)
	filter := bson.M{"user_name": userName, "company_id": companyId}
	err := userMapper.collection(ctx).FindOne(ctx, filter).Decode(loginUser)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return loginUser
}
func (userMapper *SysUserMapper) SelectUserById(ctx context.Context, userId int64) (sysUser *systemModels.SysUserVo) {
	sysUser = new(systemModels.SysUserVo)
	filter := bson.M{"_id": userId}
	err := userMapper.collection(ctx).FindOne(ctx, filter).Decode(sysUser)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return sysUser
}

func (userMapper *SysUserMapper) SelectUserList(ctx context.Context, user *systemModels.SysUserDQL) (list []*systemModels.SysUserVo, total int64) {

	//if user.Phonenumber != "" {
	//	sql += " AND u.phonenumber like concat('%', :phonenumber, '%')"
	//}
	//if user.BeginTime != "" {
	//	sql += " AND date_format(u.create_time,'%y%m%d') >= date_format(:begin_time,'%y%m%d')"
	//}
	//if user.EndTime != "" {
	//	sql += " AND date_format(u.create_time,'%y%m%d') <= date_format(:end_time,'%y%m%d')"
	//}

	filter := bson.M{"company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}

	if user.UserName != "" {
		filter["user_name"] = bson.M{"$regex": user.UserName, "$options": "i"}
	}
	if user.Status != "" {
		filter["status"] = user.Status
	}
	if user.DataScope != nil {
		filter["dept_id"] = bson.M{"$in": user.DataScope}
	}
	if user.DeptId != 0 {
		filter["dept_id"] = user.DeptId
	}
	return datasource.MongoQueryListAndTotal(ctx, userMapper.collection(ctx), list, filter, user)
}

func (userMapper *SysUserMapper) SelectUserListAll(ctx context.Context, user *systemModels.SysUserDQL) (list []*systemModels.SysUserVo) {
	filter := bson.M{"company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}

	if user.UserName != "" {
		filter["user_name"] = bson.M{"$regex": user.UserName, "$options": "i"}
	}
	if user.Status != "" {
		filter["status"] = user.Status
	}
	if user.DataScope != nil {
		filter["dept_id"] = bson.M{"$in": user.DataScope}
	}
	if user.DeptId != 0 {
		filter["dept_id"] = user.DeptId
	}
	cur, err := userMapper.collection(ctx).Find(ctx, filter)
	if err != nil {
		panic(err)
	}
	defer cur.Close(ctx)
	err = cur.All(ctx, &list)
	if err != nil {
		panic(err)
	}
	return list
}

func (userMapper *SysUserMapper) DeleteUserByIds(ctx context.Context, ids []int64, be *baize.BaseEntity) {
	m := bson.M{
		"del_flag": "2",
		"user_name": bson.M{
			"$concat": []interface{}{"$user_name", "(删除)"},
		},
		"update_by":   be.UpdateBy,
		"update_name": be.UpdateName,
		"update_time": be.UpdateTime,
	}

	up := bson.M{"$set": m}

	_, err := userMapper.collection(ctx).UpdateMany(ctx, bson.M{"_id": bson.M{"$in": ids}}, up)
	if err != nil {
		panic(err)
	}
}

func (userMapper *SysUserMapper) UpdateUserAvatar(ctx context.Context, userId int64, avatar string) {
	m := bson.M{
		"avatar": avatar,
	}

	up := bson.M{"$set": m}

	_, err := userMapper.collection(ctx).UpdateByID(ctx, userId, up)
	if err != nil {
		panic(err)
	}
}
func (userMapper *SysUserMapper) ResetUserPwd(ctx context.Context, userId int64, password string) {
	m := bson.M{
		"avatar": password,
	}
	up := bson.M{"$set": m}
	_, err := userMapper.collection(ctx).UpdateByID(ctx, userId, up)
	if err != nil {
		panic(err)
	}
}

func (userMapper *SysUserMapper) SelectUserIdsByDeptIds(ctx context.Context, deptIds []int64) (list []int64) {

	filter := bson.M{"dept_id": bson.M{"$in": deptIds}, "company_id_abbreviate": baizeContext.GetCompanyIdAbbreviate(ctx)}

	opt := &options.FindOptions{}
	opt.SetProjection(bson.M{"_id": 1})

	cursor, err := userMapper.collection(ctx).Find(ctx, filter, opt)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	defer cursor.Close(ctx)
	for cursor.Next(ctx) {
		var result struct {
			Id int64 `bson:"_id"`
		}
		if err = cursor.Decode(&result); err != nil {
			panic(err)
		}
		list = append(list, result.Id)
	}

	return list
}
func (userMapper *SysUserMapper) SelectPasswordByUserId(ctx context.Context, userId int64) string {
	filter := bson.M{"_id": userId}

	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.M{"_id": 0, "password": 1})
	var result struct {
		Password string `bson:"password"`
	}
	err := userMapper.collection(ctx).FindOne(ctx, filter, opt).Decode(result)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}

	return result.Password
}
